﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Topping.Core.Logic;
using Topping.Core.Logic.Threads;
using TopMachine.Topping.Dto;
using TopMachine.Topping.Common.Structures;
using Topping.Core.Data.Db4o;
using System.ServiceModel;
using System.ServiceModel.Channels;
using TopMachine.Desktop.Configuration;
using System.Windows.Forms;
using Topping.Core.Proxy.Local.Client;
using TopMachine.Desktop.Overall;

namespace Topping.Core.Proxy.Local
{
    internal class ServerProxy : ClientBase<IProxy>, IProxy, IDisposable
    {


        #region Properties
        public string UserName { get; set; }
        #endregion

        public Guid guidPlayer = Guid.Empty;
        Guid MemoryCheckId;

        int error = 0;

        public ServerProxy(string endpointConfigurationName)
            : base(endpointConfigurationName, Configuration.Instance.Urls.ToppingService)
        {
            MemoryCheckId = MemoryCheck.Register(this, this.GetType().FullName);

            if (RoomMessageProcessor.Instance != null)
            {
                RoomMessageProcessor.Instance.StartService();
            }
            if (MessageProcessor.Instance != null)
            {
                MessageProcessor.Instance.StartService();
            }


        }

        public object Invoke(string methodName, params object[] parameters)
        {
            object result;
            try
            {
                lock (syncRoot)
                {
                    if (OperationContext.Current == null)
                    {
                        AddCustomHeaderUserInformationFromInstance(guidPlayer);
                    }
                    
                    var clientMethod = base.Channel.GetType().GetMethod(methodName);
                    result = clientMethod == null ? null : clientMethod.Invoke(base.Channel, parameters);
                    error = 0;
                    return result; 

                }
            }
            catch (Exception ee)
            {
                lock (syncRoot)
                {
                    NLog.LogManager.GetLogger("wcf").ErrorException(methodName, ee);
                    error += 1;
                    if (error > 1)
                    {
                        System.Windows.Forms.Application.ExitThread();  
                        System.Windows.Forms.Application.Exit();
                        System.Environment.Exit(0);   
                        return null;
                    }
                    DialogResult dr = MessageBox.Show("Une erreur s'est produite, réessayez ou annulez", "Erreur de réseau : " + methodName, MessageBoxButtons.RetryCancel);
                   
                    if (dr == DialogResult.Cancel)
                    {
                        System.Windows.Forms.Application.Exit();
                        System.Environment.Exit(0);   
                        return null;
                    }


                    instance.Dispose();
                    instance = null;
                    instance = new ServerProxy("ToppingProxy");

                    if (OperationContext.Current == null)
                    {
                        AddCustomHeaderUserInformationFromInstance(guidPlayer);
                    }
                }

                return instance.Invoke(methodName, parameters);

            }

        }


        public void InvokeGetMessages(string methodName, params object[] parameters)
        {
            List<MessageDto> messages;
            try
            {
                lock (syncRoot)
                {
                    if (OperationContext.Current == null)
                    {
                        AddCustomHeaderUserInformationFromInstance(guidPlayer);
                    }
                    var clientMethod = base.Channel.GetType().GetMethod(methodName);
                    messages = clientMethod.Invoke(base.Channel, parameters) as List<MessageDto>;
                    MessageProxy.Proxy.QueueMessages(messages);
                    error = 0;
                }

            }
            catch (Exception ee)
            {
                lock (syncRoot)
                {
                    NLog.LogManager.GetLogger("wcf").ErrorException(methodName, ee);
                    error += 1;
                    if (error > 1)
                    {
                        System.Windows.Forms.Application.ExitThread();  
                        System.Windows.Forms.Application.Exit();
                        System.Environment.Exit(0);      
                        return ;

                    }
                    DialogResult dr = MessageBox.Show("Une erreur s'est produite, réessayez ou annulez", "Erreur de réseau : " + methodName, MessageBoxButtons.RetryCancel);
                  
                    if (dr == DialogResult.Cancel)
                    {
                        System.Windows.Forms.Application.Exit();
                        System.Environment.Exit(0);   
                    }


                    instance.Dispose();
                    instance = null;
                    instance = new ServerProxy("ToppingProxy");

                    if (OperationContext.Current == null)
                    {
                        AddCustomHeaderUserInformationFromInstance(guidPlayer);
                    }
                }

                 instance.InvokeGetMessages(methodName, parameters);

            }

        }

        public void AddCustomHeaderUserInformationFromInstance(Guid userId)
        {
            Instance.guidPlayer = userId;
            AddCustomHeaderUserInformation(new OperationContextScope(base.InnerChannel), userId);

        }

        private static void AddCustomHeaderUserInformation(
                      OperationContextScope scope, Guid userId)
        {
            MessageHeader header
              = MessageHeader.CreateHeader(
              "UserID",
              "CustomHeader",
              userId
              );

            if (OperationContext.Current.OutgoingMessageHeaders.Count == 0)
            {
                OperationContext.Current.OutgoingMessageHeaders.Add(header);
            }
        }

        #region Singleton
        private static volatile ServerProxy instance;
        private static object syncRoot = new Object();

        public static ServerProxy Instance
        {
            get
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {

                        if (instance == null)
                            instance = new ServerProxy("ToppingProxy");
                    }
                }

                return instance;
            }

        }
        #endregion

        #region ServerState
        GameServerState gameServerState = null;
        public GameServerState GetServerState()
        {
            if (gameServerState == null)
            {
                gameServerState = GameServerState.Instance;
            }
            return gameServerState;
        }


        #endregion

        #region Chatting

        public void ActivateChat()
        {
            Invoke("ActivateChat", null);
        }

        public bool CheckVersion(string version)
        {
            return (bool)Invoke("CheckVersion", new object[] { version });
        }

        public void DeactivateChat()
        {
            Invoke("DeactivateChat", null);
        }


        public void SendMessage(MessageDto m)
        {
            Invoke("SendMessage", new object[] { m });
        }


        public List<MessageDto> GetMessages()
        {
            InvokeGetMessages("GetMessages", null);
            return null;
        }

        #endregion

        #region Login

        public List<UserDto> GetUsers()
        {
            List<UserDto> lst = (List<UserDto>)Invoke("GetUsers",null);
            return lst;
        }
        public bool ChangedPwdUser(UserDto us, string NewPwd)
        {
            bool ok = (bool)Invoke("ChangedPwdUser", new object[] { us,NewPwd});
            return ok;
        }
       
        public bool UpdateUser(UserDto us)
        {
            bool ok = (bool)Invoke("UpdateUser", new object[] { us});
            return ok;
        }

        public bool DeleteUser(UserDto us)
        {
            bool ok = (bool)Invoke("DeleteUser", new object[] { us });
            return ok;
        }
        public Guid Login(string userName, string passWord, int version)
        {
            Guid g = (Guid)Invoke("Login", new object[] { userName, passWord, version });
            Instance.AddCustomHeaderUserInformationFromInstance(g);
            return g;
        }

        public void Logoff()
        {
            Invoke("Logoff", null);
        }
        #endregion

        #region ROOMS

        public void SendMessageToRoom(int x, MessageDto m)
        {
            Invoke("SendMessageToRoom", new object[] { x, m });
        }

        public RoomDto GetRoom(int roomid)
        {
            return (RoomDto)Invoke("GetRoom", new object[] { roomid });
        }

        //public List<Room> GetRooms()
        //{
        //    return base.Channel.GetRooms();
        //}

        public List<RoomDto> GetRoomsDto()
        {
            return (List<RoomDto>)Invoke("GetRoomsDto", null);
        }

        #endregion

        #region Room

        public void ResetRooms()
        {
            Invoke("ResetRooms", null);
        }

        public RoomDto InitRoom(Room room, bool generate)
        {
            return (RoomDto)Invoke("InitRoom", new object[] { room, generate });
        }


        public RoomDto JoinRoom(int roomId)
        {
            return (RoomDto)Invoke("JoinRoom", new object[] { roomId });
        }

        public void LeaveAnyRoom()
        {
            Invoke("LeaveAnyRoom", null);
        }

        public RoomDto LeaveRoom()
        {
            return (RoomDto)Invoke("LeaveRoom", null); ;
        }
        public string[] ListPlayers()
        {
            return (string[])Invoke("ListPlayers", null);
        }

        public string[] ListRoomPlayers(int roomid)
        {
            return (string[])Invoke("ListRoomPlayers", new object[] { roomid });
        }

        public string[] ListRoomActivePlayers(int roomid)
        {
            return (string[])Invoke("ListRoomActivePlayers", new object[] { roomid });
        }

        #endregion

        #region Game
        public GeneratedGameDto GetGame()
        {
            return (GeneratedGameDto)Invoke("GetGame", null);
        }

        public void SetGame(GeneratedGameDto game)
        {
            Invoke("SetGame", new object[] { game });
        }

        public void GetListPlayedRound(string playerSearch)
        {
            Invoke("GetListPlayedRound", new object[] { playerSearch });
        }

        public void AddPlayedRound(PlayerSummaryDto summary, PlayedGameRoundDto pgr)
        {
            Invoke("AddPlayedRound", new object[] { summary, pgr });
        }

        public void FinishGame()
        {
            Invoke("FinishGame", null); ;
        }
        public FinalRoomDto GetFinalRoom(int RoomId)
        {
            return (FinalRoomDto)Invoke("GetFinalRoom", new object[] { RoomId });
        }

        public void StartGame()
        {
            Invoke("StartGame", null);
        }

        public List<GamesDetailDto> GetGamesDetail(string player, int year, int mont, Guid configId)
        {
            return (List<GamesDetailDto>)Invoke("GetGamesDetail", new object[] { player, year, mont, configId });
        }
        #endregion

        #region Configuration
        public List<ConfigGameDto> GetConfigurations()
        {
            return (List<ConfigGameDto>)Invoke("GetConfigurations", null);
        }

        public bool UpdateConfiguration(ConfigGameDto cfg)
        {
            return (bool)Invoke("UpdateConfiguration", new object[] { cfg });
        }

        public bool DeleteConfiguration(ConfigGameDto cfg)
        {
            return (bool)Invoke("DeleteConfiguration", new object[] { cfg });
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            MemoryCheck.Unregister(MemoryCheckId);
            if (RoomMessageProcessor.Instance != null)
            {
                RoomMessageProcessor.Instance.StopService();
            }
            if (MessageProcessor.Instance != null)
            {
                MessageProcessor.Instance.StopService();
            }
        }

        #endregion



        #region IProxy Members


        public List<RankingDto> GetRankings(string player, int year, int mont, Guid ConfigId)
        {
            throw new NotImplementedException();
        }

        #endregion


        public bool DeleteGameXML(string fn)
        {
            throw new NotImplementedException();
        }
    }
}
